/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.algoritmo;


import com.controller.Constantes;
import com.persistencia.domain.*;
import com.service.*;
import com.service.impl.*;
import com.util.ReporteHorario;
import com.util.ReporteHorariovista;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;

/**
 *
 * @author SHERLY
 */
public class AGPrincipal implements Serializable{
    
    //<editor-fold defaultstate="collapsed" desc="Atributos">
    
    //Clase
    private ClaseService claseService;
    private List<Clase> listaClase;
    
    //Asignatura
    private AsignaturaService asignaturaService;
    private List<Asignatura> listaAsignatura;
    
    //DocentexClase
    private DocentexClaseService docentexClaseService;
    private List<Docentexclase> listaDocentexClase;
    
    //Salon
    private SalonService salonService;
    private List<Salon> listaSalon;
    
    //Docente
    private DocenteService docenteService;
    private List<Docente> listaDocente;
    
    //Periodo
    private PeriodoService periodoService;
    private List<Periodo> listaPeriodo;
    
    //DocenteXPeriodo
    private DocentePeriodoService docentePeriodoService;
    private List<Docentexperiodo> listaDocenteXPeriodo;
    
    //ClaseXClase
    private ClaseXClaseService claseXClaseService;
    private List<Clasexclase> listaClaseXClase;
    
    //AsignaturaXPeriodo
    private AsignaturaXPeriodoService asignaturaXPeriodoService;
    private List<Asignaturaxperiodo> listaAsignaturaXPeriodo;
    
    //ClaseXSalon
    private ClaseXSalonService claseXSalonService;
    private List<Clasexsalon> listaClaseXSalon;
    
    //PeriodoXSalon
    private PeriodoXSalonService periodoXSalonService;
    private List<Periodoxsalon> listaPeriodoXSalon;
    
    //CicloAcademico
    private CicloAcademicoService cicloAcademicoService;
    private List<Cicloacademico> listaCicloAcademico;
    
    private List<List<Periodo>> listaPeriodosXDia;
    private List<HashMap<Integer, HashMap<Integer, Docentexclase>>> listaHorarios;
    private List<Integer> listaHorariosFA;
        
    private HashMap<Integer, HashMap<Integer, Boolean>> listaHMClaseConflicto;
    private HashMap<Integer, HashMap<Integer, Clasexsalon>> listaHMClaseXSalon;
    private HashMap<Integer, HashMap<Integer, Asignaturaxperiodo>> listaHMAsignaturaXPeriodo;
    private HashMap<Integer, HashMap<Integer, Docentexperiodo>> listaHMDocenteXPeriodo;
    //Para evitar crear instancias diferentes
    HashMap<Integer, HashMap<Integer, Docentexclase>> listaHMHorarioSalon;
    HashMap<Integer, Docentexclase> listaHMHorarioPeriodo;
    int nDia;
    Periodo periodo;
    int altrHorarios, altrHorarios2, faPadre, faPadre2;
    List<List<Clase>> listaClasesXCiclosXPeriodo;
    List<List<Integer>> listaClasesXPeriodoXCiclosXDia;
    List<String> listahoras = new ArrayList<String>();;
    int nSlnIdAlt;
    int altrPeriodo;
    int altrSalon;
    int nSlnId01 = 0, nSlnId02 = 0, nPosPrdId01 = 0, nPosPrdId02 = 0;
    /////
    //private int cntRestDuras = 0;
    private int cntRD02 = 0;
    private int cntRD05 = 0;
    private int cntRD07 = 0;
    private int cntRD09 = 0;
    private int cntRD10 = 0;
    private int cntRD11 = 0;
    private int cntRestBlandas = 0;
    private int vFuncionAptitud = 12;
    
    int indicemejorsolucion;
    public double Pc;
    public double Pm;
    public int parada;
    private int nSlnId;
    private int nPrdId;
    private int nPosPrd;
    private int horasMaxClaseConsXDia;
    private int horasMaxClaseTotalXDia;
    
    int indicepeorsolucion = 0;
    private Docentexclase docentexClaseaux;
    private Docentexclase docentexClaseaux1;
    private boolean bandN01;
    private boolean bandN02;
    private String matrizHorario[][];
    
    Constantes constantes;
    private int vfunciondeadaptacion = 0;
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Inicializar">
    public AGPrincipal() {
        inicializar();
        constantes = new Constantes();
        /*Pc = Constantes.probCruzamiento;
        Pm = Constantes.probMutacion;
        parada = Constantes.cantIteracion;*/
        Pc = Double.parseDouble(constantes.getProbCruzamiento());
        Pm = Double.parseDouble(constantes.getProbMutacion());
        parada = Integer.parseInt(constantes.getCantIteracion());
        horasMaxClaseConsXDia = Integer.parseInt(constantes.getHorasMaxClaseConsXDia());
        horasMaxClaseTotalXDia = Integer.parseInt(constantes.getHorasMaxClaseTotalXDia());
        listaClasesXCiclosXPeriodo = new ArrayList<List<Clase>>();
        listaClasesXPeriodoXCiclosXDia = new ArrayList<List<Integer>>();  
    }
    
    private void inicializarListaClasesXPeriodoXCiclosXDia(){

        for (int i = 0; i < listaCicloAcademico.size(); i++) {
            listaClasesXPeriodoXCiclosXDia.get(i).clear();
            for (int j = 0; j < 14; j++) {
                listaClasesXPeriodoXCiclosXDia.get(i).add(j, 0);
            }
        }
    }
    
    private void inicializar(){
        //Clase
        claseService = new ClaseServiceImpl();
        listaClase = new ArrayList<Clase>();
        //Clase
        asignaturaService = new AsignaturaServiceImpl();
        listaAsignatura = new ArrayList<Asignatura>();
        //DocentexClase
        docentexClaseService = new DocentexClaseServiceImpl();
        listaDocentexClase = new ArrayList<Docentexclase>();
        //Docente
        docenteService = new DocenteServiceImpl();
        listaDocente = new ArrayList<Docente>() ;
        //Salon
        salonService = new SalonServiceImpl();
        listaSalon = new ArrayList<Salon>(); 
        //Periodo
        periodoService = new PeriodoServiceImpl();
        listaPeriodo = new ArrayList<Periodo>();
        //DocenteXPeriodo
        docentePeriodoService = new DocentePeriodoServiceImpl();
        listaDocenteXPeriodo = new ArrayList<Docentexperiodo>();
        
        //ClaseXClase
        claseXClaseService = new ClaseXClaseServiceImpl();
        listaClaseXClase = new ArrayList<Clasexclase>();
        
        //AsignaturaXPeriodo
        asignaturaXPeriodoService = new AsignaturaXPeriodoServiceImpl();
        listaAsignaturaXPeriodo = new ArrayList<Asignaturaxperiodo>();
        //ClaseXSalon
        claseXSalonService = new ClaseXSalonServiceImpl();
        listaClaseXSalon = new ArrayList<Clasexsalon>();
        //PeriodoXSalon
        periodoXSalonService = new PeriodoXSalonServiceImpl();
        listaPeriodoXSalon = new ArrayList<Periodoxsalon>();        
        //CicloAcademico
        cicloAcademicoService = new CicloAcademicoServiceImpl();
        listaCicloAcademico = new ArrayList<Cicloacademico>();
    
        listahoras = new ArrayList<String>();
        listahoras.clear();
        listahoras.add("8:00-9:00");
        listahoras.add("9:00-10:00");
        listahoras.add("10:00-11:00");
        listahoras.add("11:00-12:00");
        listahoras.add("12:00-13:00");
        listahoras.add("13:00-14:00");
        listahoras.add("14:00-15:00");
        listahoras.add("15:00-16:00");
        listahoras.add("16:00-17:00");
        listahoras.add("17:00-18:00");
        listahoras.add("18:00-19:00");
        listahoras.add("19:00-20:00");
        listahoras.add("20:00-21:00");
        listahoras.add("21:00-22:00");
        //listahoras.add("10:00-11:00");
    }
    
    public void obtenerDataParaAG(){
        try {
            listaClase = claseService.obtenerListaClase();
            System.out.println("listaClase,size="+listaClase.size());
            
            listaAsignatura = asignaturaService.obtenerListaAsignaturas();
            System.out.println("listaAsignatura,size="+listaAsignatura.size());
            
            listaDocentexClase = docentexClaseService.
                    obtenerListaDocenteXClasePorCiclo(new Ciclo(1));
            System.out.println("listaDocentexClase,size="+listaDocentexClase.size());
            
            listaDocente = docenteService.obtenerListaDocentes();
            System.out.println("listaDocente,size="+listaDocente.size());
            
            listaSalon = salonService.obtenerListaSalon();
            System.out.println("listaSalon,size="+listaSalon.size());
            
            listaPeriodo = periodoService.obtenerListaPeriodo();
            System.out.println("listaPeriodo,size="+listaPeriodo.size());
            inicializarlistaPeriodosXDia();
            
            listaDocenteXPeriodo = docentePeriodoService.obtenerListaDocentePeriodos();
            System.out.println("listaDocenteXPeriodo,size="+listaDocenteXPeriodo.size());
            inicializarMatrizDocentePeriodo();
            
            listaClaseXClase = claseXClaseService.obtenerListaClaseXClase();
            System.out.println("listaClaseXClase,size="+listaClaseXClase.size());
            inicializarMatrizClaseConflicto();
            
            listaAsignaturaXPeriodo = asignaturaXPeriodoService.obtenerListaAsignaturaXPeriodo();
            System.out.println("asignaturaXPeriodo,size="+listaAsignaturaXPeriodo.size());
            inicializarMatrizAsignaturaPorPeriodo();
            
            //Inicializamos la Matriz Clase Por Salón                         
            listaClaseXSalon = claseXSalonService.obtenerListaClaseXSalon();
            System.out.println("listaClaseXSalon,size="+listaClaseXSalon.size());            
            inicializarMatrizClasePorSalon();
            
            listaCicloAcademico = cicloAcademicoService.obtenerListaCicloAcademicos();
            System.out.println("listaCicloAcademico,size="+listaCicloAcademico.size());    
            
            listaPeriodoXSalon = periodoXSalonService.buscarperiodoxsalonxIdHorario(new Horario(1));
            System.out.println("listaPeriodoXSalon,size="+listaPeriodoXSalon.size());    
            
            matrizHorario = new String [listaSalon.size()][listaPeriodo.size()];
            
            for (int i = 0; i < listaCicloAcademico.size(); i++) {
                listaClasesXPeriodoXCiclosXDia.add(new ArrayList<Integer>());    
                //listaClasesXCiclosXPeriodo.add(new ArrayList<Clase>());
            }
            inicializarListaClasesXPeriodoXCiclosXDia();
        } catch (Exception ex) {
            Logger.getLogger(AGPrincipal.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
        
    //Inicializa la listaHMDocenteXPeriodo y luego agrega DocenteXPeriodo
    private void inicializarMatrizDocentePeriodo(){
    	listaHMDocenteXPeriodo = new HashMap<Integer, HashMap<Integer, Docentexperiodo>>();
        int nDcnId;
        //Inicializamos la lista para cada Docente
        for (int i = 0; i < listaDocente.size(); i++) {
            nDcnId = listaDocente.get(i).getNDcnId();
            listaHMDocenteXPeriodo.put(nDcnId, new HashMap<Integer, Docentexperiodo>());                
        }
        //Recorremos la listaDocenteXPeriodo para agregarlos a listaHMDocenteXPeriodo 
        for (int i = 0; i < listaDocenteXPeriodo.size(); i++) {
            nDcnId = listaDocenteXPeriodo.get(i).getDocente().getNDcnId();
            //Para cada docente se agrega un DocenteXPeriodo con la llave del Periodo
            listaHMDocenteXPeriodo.get(nDcnId).put(
                    listaDocenteXPeriodo.get(i).getPeriodo().getNPrdId(), listaDocenteXPeriodo.get(i));
        }
    }
    
    //Llena la matriz listaPeriodosXDia con los periodos
    private void inicializarlistaPeriodosXDia(){
        listaPeriodosXDia = new ArrayList<List<Periodo>>();
        for (int i = 0; i < 7; i++) {
            listaPeriodosXDia.add(new ArrayList<Periodo>());
        }        
        for (Periodo periodo : listaPeriodo) {
            listaPeriodosXDia.get(periodo.getNDia()-1).add(periodo);
        }
    }
    
    //Inicializa la listaHMClaseConflicto y luego agrega ClaseXClase    
    private void inicializarMatrizClaseConflicto(){        
        listaHMClaseConflicto = new HashMap<Integer, HashMap<Integer, Boolean>>();        
        int nClsId;
        //System.out.println("listaClase.size()="+listaClase.size());
        //Agregamos una lista vacía a todas las clases en la listaHMClaseConflicto
        for (int i = 0; i < listaClase.size(); i++){
            listaHMClaseConflicto.put(listaClase.get(i).getNClsId(), new HashMap<Integer, Boolean>());
        }
        //Agregamos las clases conflictivas
        for (int i = 0; i < listaClaseXClase.size(); i++) {
            nClsId = listaClaseXClase.get(i).getClase().getNClsId();
            //Se agrega solo las clases con Conflicto
            listaHMClaseConflicto.get(nClsId).put(
                    listaClaseXClase.get(i).getClase1().getNClsId(), Boolean.TRUE);            
        }        
    }
    
    //Inicializa la listaHMAsignaturaXPeriodo y luego agrega AsignaturaXPeriodo
    private void inicializarMatrizAsignaturaPorPeriodo(){
        int nAsgId;
        listaHMAsignaturaXPeriodo = new HashMap<Integer, HashMap<Integer, Asignaturaxperiodo>>();
        //System.out.println("listaAsignatura.size()="+listaAsignatura.size());
        //Agregamos una lista vacía a todas las Asignaturas en la listaHMAsignaturaXPeriodo
        for (int i = 0; i < listaAsignatura.size(); i++) {
            listaHMAsignaturaXPeriodo.put(listaAsignatura.get(i).getNAsgId(), new HashMap<Integer, Asignaturaxperiodo>());
        }
        //Agrega,ps los Periodos permitidos para el dictado de esa clase
        for (int i = 0; i < listaAsignaturaXPeriodo.size(); i++) {
            nAsgId = listaAsignaturaXPeriodo.get(i).getAsignatura().getNAsgId();
            listaHMAsignaturaXPeriodo.get(nAsgId).put(
                    listaAsignaturaXPeriodo.get(i).getPeriodo().getNPrdId(), 
                    listaAsignaturaXPeriodo.get(i));
        }
    }
    
    //Inicializa la listaHMClaseXSalon y luego agrega ClaseXSalon
    private void inicializarMatrizClasePorSalon(){        
        listaHMClaseXSalon = new HashMap<Integer, HashMap<Integer, Clasexsalon>>();
        int nDcnCls1Id;
        //Inicializamos la lista para cada clase
        for (int i = 0; i < listaDocentexClase.size(); i++) {
            nDcnCls1Id = listaDocentexClase.get(i).getNDcnClsId();
            listaHMClaseXSalon.put(nDcnCls1Id, new HashMap<Integer, Clasexsalon>());                
        }
        //Recorremos la listaClaseXSalon para agregarlos a listaHMClaseXSalon 
        for (int i = 0; i < listaClaseXSalon.size(); i++) {
            nDcnCls1Id = listaClaseXSalon.get(i).getClasexsalonPK().getNDcnCls1Id();
            //Para cada clase se agrega una ClaseXSalon con la llave del salón
            listaHMClaseXSalon.get(nDcnCls1Id).put(
                    listaClaseXSalon.get(i).getSalon().getNSlnId(), listaClaseXSalon.get(i));
        }
    }
        
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Inicializar Individuos">            
    public void inicializarPoblacion(){
        listaHorarios = new ArrayList<HashMap<Integer, HashMap<Integer, Docentexclase>>>();
        listaHorariosFA = new ArrayList<Integer>();
        for (int i = 0; i < Integer.parseInt( constantes.getTamanoPoblacion()); i++) {
       //     System.out.println("Individuo: "+(i+1));
            listaHorarios.add(i, inicializarIndividuo());
            listaHorariosFA.add(i,evaluarFuncionAptitud(listaHorarios.get(i)));
        }
        System.out.println("Se inicializó la población en "+constantes.getTamanoPoblacion()+" individuos");
    }
    
    public HashMap<Integer, HashMap<Integer, Docentexclase>> inicializarHorario(){
        listaHMHorarioSalon = new HashMap<Integer, HashMap<Integer, Docentexclase>>();        
        for (Salon salon : listaSalon) {
            listaHMHorarioPeriodo = new HashMap<Integer, Docentexclase>();
            for (Periodo periodo : listaPeriodo) {
                listaHMHorarioPeriodo.put(periodo.getNPrdId(), null);
            }
            listaHMHorarioSalon.put(salon.getNSlnId(), listaHMHorarioPeriodo);                
        }
        return listaHMHorarioSalon;
    }
    
    public HashMap<Integer, HashMap<Integer, Docentexclase>> inicializarIndividuo(){
        int altrSalon;
        int altrPeriodo;
        boolean asignado;
        try {
            //Inicializar un HORARIO            
            listaHMHorarioSalon = inicializarHorario();            
            //Inicializamos variables
            //listaHMHorarioPeriodo = new HashMap<Integer, Docentexclase>();
//            listaDocentexClase = docentexClaseService.obtenerListaDocenteXClasePorCiclo(new Ciclo(1));
            //System.out.println("listaDocentexClase,size="+listaDocentexClase.size());
            int nHoras;
            //System.out.println("listaSalon.size()="+listaSalon.size());
            //System.out.println("listaPeriodo.size()="+listaPeriodo.size());
            /*A cada Clase se le asignará un salón y varios periodos
             * deben de ser consecutivo y en el mismo día
            */
            for(int i = 0; i < listaDocentexClase.size(); i++){
                //System.out.println(""+listaDocentexClase.get(i).getNClsId().getNAsgId().getVNombre() +" Numero: "+listaDocentexClase.get(i).getNDcnClsId());
                asignado = false;
                while( !asignado ){
                    altrSalon = aleatorio(listaSalon.size()-1,false);
                    altrPeriodo = aleatorio(listaPeriodo.size()-1,false);
                    nSlnId = listaSalon.get(altrSalon).getNSlnId();
                    nHoras = listaDocentexClase.get(i).getNClsId().getNHoras().intValue();
                    //System.out.println("altrSalon="+altrSalon);
                    //System.out.println("altrPeriodo="+altrPeriodo);
                    if( evaluarPeriodoYSalonPorAsignar(nHoras,
                            listaDocentexClase.get(i).getNDcnClsId(),
                            nSlnId,altrPeriodo,listaHMHorarioSalon) ){
                        asignado = true;       
                        //asignamos el DocenteXClase al horario
                        for (int j = 0; j < nHoras; j++) {
                            listaHMHorarioSalon.get(nSlnId).
                                    put(listaPeriodo.get(altrPeriodo+j).getNPrdId(), 
                                        listaDocentexClase.get(i));
                        }
                    }
                }
            }
            /*System.out.println("Imprimimos los valores==============================");
            int contfilas = 1;
            int contcolumnas = 1;
            
            for ( Salon salon : listaSalon ) {
                System.out.println(""+salon.getNSlnId()+listaHorarioSalon.get(salon.getNSlnId())+" = ");
                contcolumnas = 1;
                for (Periodo periodo : listaPeriodo) {
                    Docentexclase docenteXClase = listaHorarioSalon.get(salon.getNSlnId()).get(periodo.getNPrdId());
                    if( docenteXClase == null )
                        System.out.println("null"+",("+contfilas+","+contcolumnas+")");
                    else 
                        System.out.println(docenteXClase.getNClsId().getNAsgId().getVNombre()+",("+contfilas+","+contcolumnas+")");
                    listaHorarioPeriodo.put(periodo.getNPrdId(), null);
                    contcolumnas++;
                }
                
                System.out.println("================================================");
                contfilas++;
            }*/
        } catch (Exception ex) {
            Logger.getLogger(AGPrincipal.class.getName()).log(Level.SEVERE, null, ex);
        }
        return listaHMHorarioSalon;
    }
    
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Métodos Varios">
    
    //obtiene un aleatorio, band: consida el 0 un valor NO válido
    private int aleatorio(int max, boolean band){
        int altr;
        do{
            altr = (int)(Math.random()*max);            
        }while(altr == 0 && band);        
        return altr;
    }
    
    //Evalua si el periodo es apto para asignar y el salón es apto
    private boolean evaluarPeriodoYSalonPorAsignar(int nHoras,int nDcnClsId, int nSlnId, int posPeriodo, 
                                    HashMap<Integer, HashMap<Integer, Docentexclase>> listaHMHorarioSalon){            
        if( listaHMClaseXSalon.get(nDcnClsId).get(nSlnId) == null ){
            //No es un salón válido para esa clase
            return false;
        }
        if( listaPeriodo.size() <= (posPeriodo+nHoras) ){
            //La cantidad de horas sobrepasa el límite
            return false;
        }
        nDia = listaPeriodo.get(posPeriodo).getNDia();
        for (int j = 0; j < nHoras; j++) {
            periodo = listaPeriodo.get(posPeriodo+j);
            if( listaHMHorarioSalon.get(nSlnId).get(periodo.getNPrdId()) != null
                    || nDia != periodo.getNDia() ){
                //Tiene asignado un DocenteXClase
                //El día de los periodos seguidos es diferente
                return false;
            }             
        }
        return true;
    }
        
    //RD02: Evalua que el docente nDcnId no este asignado en ese periodo nPrdId
    private boolean evaluarUnicidadDocenteEnPeriodo(int nDcnId,int nSlnId, int nPrdId, HashMap<Integer, HashMap<Integer, Docentexclase>> listaHMHorarioSalon){
        Docentexclase docenteXClase;
        for(Salon salon : listaSalon){
            docenteXClase = listaHMHorarioSalon.get(salon.getNSlnId()).get(nPrdId);     
            if( docenteXClase != null  && docenteXClase.getNDcnId().getNDcnId() == nDcnId && nSlnId != salon.getNSlnId()){ 
                //Si tiene una clase se valida si el docente que queremos asignar en ese periodo
                //ya está asignado
                cntRD02++;
                return false;        
            } 
        } 
        return true;
    }
    
    //N1: mutación
    //RD02: Evalua que el docente nDcnId no este asignado en ese periodo nPrdId
    private boolean evaluarUnicidadDocenteEnPeriodoXHoras(int nHoras, int nDcnId, int nPosPrd, HashMap<Integer, HashMap<Integer, Docentexclase>> listaHMHorarioSalon){
        Docentexclase docenteXClase;
        for (int j = 0; j < nHoras ; j++) {                
            for(Salon salon : listaSalon){
                docenteXClase = listaHMHorarioSalon.get(salon.getNSlnId()).get(listaPeriodo.get(nPosPrd+j).getNPrdId());     
                if( docenteXClase != null && docenteXClase.getNDcnId().getNDcnId() == nDcnId ){ 
                    //Si tiene una clase se valida si el docente que queremos asignar en ese periodo
                    //ya está asignado
                    //System.out.println("2°"+docenteXClase.getNClsId().getNAsgId().getVNombre());
                    return false;        
                } 
            } 
        }
        return true;
    }
    
    //Para un hijo:
    //RD05: Evalua si el periodo es disponible para el docente
    //RD09: Evalua si el periodo es disponible para la clase según su ciclo
    private boolean evaluarDisponibilidadDocYAsg(int nHoras, Docentexclase docenteXClase, int posDia, int pos2Periodo){                    
        for (int j = 0; j < nHoras; j++) {
            if( pos2Periodo != -1 )
                periodo = listaPeriodosXDia.get(posDia).get(pos2Periodo+j);
            else
                periodo = listaPeriodo.get(posDia+j);
            //RD09
            if( listaHMAsignaturaXPeriodo.get(docenteXClase.getNClsId().getNAsgId().getNAsgId()).
                    get(periodo.getNPrdId()) == null ){
                //La asignatura no tiene el periodo como válido
                cntRD09++;
                return false;
            }
            //RD05
            if( listaHMDocenteXPeriodo.get(docenteXClase.getNDcnId().getNDcnId()).
                    get(periodo.getNPrdId()).getVEstado().equals("0") ){
                //El docente no tiene como disponible a ese periodo
                cntRD05++;
                return false;
            }
            //return false; 
        }
        return true;
    }

    //RD07
    private boolean evaluarConflictos(int nHoras, Docentexclase docenteXClase, int posPrd, HashMap<Integer, HashMap<Integer, Docentexclase>> horario){
        Docentexclase docenteXClase2;
        for (int j = 0; j < nHoras; j++) {
            for (Salon salon : listaSalon) {
                docenteXClase2 = horario.get(salon.getNSlnId()).get(listaPeriodo.get(posPrd+j).getNPrdId());
                //RD07
                if( docenteXClase2 != null && listaHMClaseConflicto.get(docenteXClase.getNClsId().getNClsId()).
                        get(docenteXClase2.getNClsId().getNClsId()) != null ){
                    //Si hay conflicto
                    return false;
                }
            }
        }
        return true;
    }
    
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Función de Aptitud">
    private int evaluarFuncionAptitud(HashMap<Integer, HashMap<Integer, Docentexclase>> listaHorarioSalon){
        //1º validamos claseXClase : Que no haya conflicto
        int cnt,cnt2;
        cntRestBlandas = 0;
        cntRD02 = 0;
        cntRD05 = 0;
        cntRD07 = 0;
        cntRD09 = 0;
        cntRD10 = 0;
        cntRD11 = 0;
        
        List<Clase> listaClases;
        Clase clase;
                
        Docentexclase docenteXClase;
        int nCicAcdId;
        int i, j, k;
        for (int l = 0; l < listaPeriodosXDia.size(); l++) {
            //RD11: Inicializa el vector listaClasesXCiclosXPeriodoXDia            
            inicializarListaClasesXPeriodoXCiclosXDia();
            //Fin 1. RD11
            //Para cada día se recorren los periodos
            for (int m = 0; m < listaPeriodosXDia.get(l).size(); m++) {
                //Llenamos el vector con las clases que pertenecen a un ciclo
                listaClasesXCiclosXPeriodo.clear();            
                for (i = 0; i < listaCicloAcademico.size(); i++) {
                    listaClasesXCiclosXPeriodo.add(new ArrayList<Clase>());
                }
                for (Salon salon : listaSalon) {
                    docenteXClase = listaHorarioSalon.get(salon.getNSlnId()).
                            get(listaPeriodosXDia.get(l).get(m).getNPrdId());
                    if( docenteXClase != null ){
                        //el horario si tiene asignado un docenteXClase
                        nCicAcdId = docenteXClase.getNClsId().getNAsgId().getNCicAcdId().getNCicAcdId();
                        
                        //RD02
                        evaluarUnicidadDocenteEnPeriodo(docenteXClase.getNDcnId().getNDcnId(),salon.getNSlnId(),
                                listaPeriodosXDia.get(l).get(m).getNPrdId(),listaHorarioSalon);                         
                        //Fin 2. RD02
                        //RD05: Evalua si el periodo es disponible para el docente
                        //RD09: Evalua si el periodo es disponible para la clase según su ciclo
                        //RD09
                        if( listaHMAsignaturaXPeriodo.get(docenteXClase.getNClsId().getNAsgId().getNAsgId()).
                                get(listaPeriodosXDia.get(l).get(m).getNPrdId()) == null ){
                            //La asignatura no tiene el periodo como válido
                            cntRD09++;
                        }
                        //Fin 2. RD09
                        //RD05
                        if( listaHMDocenteXPeriodo.get(docenteXClase.getNDcnId().getNDcnId()).
                                get(listaPeriodosXDia.get(l).get(m).getNPrdId()).getVEstado().equals("0") ){
                            //El docente no tiene como disponible a ese periodo
                            cntRD05++;
                        }
                        //Fin 2. RD05
                        //RD11
                        listaClasesXPeriodoXCiclosXDia.get(nCicAcdId-1).set(m,1);
                        listaClasesXCiclosXPeriodo.get(nCicAcdId-1).add(docenteXClase.getNClsId());
                        //Fin 2. RD11                                                                    
                    }
                    /////////////////////////////////////////////
                }
                //Recorremos el vector de ciclos para evaluar que clases tienen conflictos
                for (int p = 0; p < listaClasesXCiclosXPeriodo.size(); p++) {             
                    if( listaClasesXCiclosXPeriodo.get(p).size() > 1 ){
                        //System.out.println("ciclo="+(i+1)+",cant="+listaClasesXCiclos.get(i).size());
                        listaClases = listaClasesXCiclosXPeriodo.get(p);                       
                        for (int w = 0; w < listaClases.size()-1; w++) {
                            clase = listaClases.get(w);
                            //System.out.println("clase="+clase.getNClsId());
                            //System.out.println("clase="+clase.getNClsId()+",j="+j);
                            for (k = w+1; k < listaClases.size(); k++) {
                                if( listaHMClaseConflicto.get(
                                        clase.getNClsId()).get(listaClases.get(k).getNClsId()) != null ){
                                    //Si hay conflicto => penalizamos
                                    //System.out.println("màs:getNClsId()="+listaClases.get(k).getNClsId());
                                    cntRD07++;
                                }                
                            }
                        }
                    }
                }              
            }
            ///Se validará por cada ciclo todos los periodos que tienen al menos 1 clase
            for (int g = 0; g < listaClasesXPeriodoXCiclosXDia.size(); g++) {
                cnt = 0;                
                for (j = 0; j < listaClasesXPeriodoXCiclosXDia.get(g).size(); j++) {
                    //RD11: Recorremos el vector de clases por ciclos por día
                    //System.out.println("i="+i+",j="+j);
                    if( listaClasesXPeriodoXCiclosXDia.get(g).get(j) > 0 ){                        
                        cnt++;
                    }
                    //Fin. RD11
                    //Por cada ciclo analizaremos los periodos
                    //RD 10: Validamos cantidad de horas consecutivas por día
                    cnt2 = 1;
                    for (k = j+1; k < listaClasesXPeriodoXCiclosXDia.get(g).size(); k++) {
                        //RD10: Recorremos el vector de clases por ciclos por día
                        if( listaClasesXPeriodoXCiclosXDia.get(g).get(k) == 0 ){                        
                            //Si es 0 se acaba
                            break;
                        }else{
                            cnt2++;
                        }          
                    }
                    if( cnt2 > horasMaxClaseConsXDia ){
                        cntRD10++;
                    }
                    //Fin. RD10
                }
                if( cnt > horasMaxClaseTotalXDia ){
                    cntRD11++;
                }
            }
        }
        vFuncionAptitud = cntRD02+cntRD05+cntRD07+cntRD09+cntRD10+cntRD11;
        //FIN 1º
        return (30*(cntRD02+cntRD05)+cntRD07+cntRD09+cntRD10+cntRD11);
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Seleccionar Padre">
    
    //con el método de Selección de torneo con tamaño igual 2 estocástico o determinístico
    //padre: posición del padre escogido anteriormente, para evitar que se escoja el mismo
    //si es el 1º padre será -1
    private int seleccionarPosicionPadre(int posPadre){
        //Evaluamos su función de aptitud y escogemos el que tiene mayor             
        do{
            altrHorarios = aleatorio(listaHorarios.size()-1,false);
        }while(altrHorarios == posPadre);
        faPadre = evaluarFuncionAptitud(listaHorarios.get(altrHorarios));
        do{
            altrHorarios2 = aleatorio(listaHorarios.size()-1,false);
        }while(altrHorarios == altrHorarios2 || altrHorarios2 == posPadre);
        faPadre2 = evaluarFuncionAptitud(listaHorarios.get(altrHorarios2));
        
        return (faPadre > faPadre2) ? altrHorarios : altrHorarios2;
    }
    
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Cruzamiento">
    
    //Realizar el cruzamiento, retornando 1 hijo
    private HashMap<Integer, HashMap<Integer, Docentexclase>> cruzarPadres(HashMap<Integer, HashMap<Integer, Docentexclase>> listaHorarioPadre1, HashMap<Integer, HashMap<Integer, Docentexclase>> listaHorarioPadre2){
        try {
            //Inicializamos el hijo
            HashMap<Integer, HashMap<Integer, Docentexclase>> horarioHijo = inicializarHorario();                        
            HashMap<Integer, HashMap<Integer, Docentexclase>> horarioPadre;
            int posPeriodo, nHoras, j, cont = 1;
            Iterator it;
            Map.Entry e;
            boolean asignoClase, band2, hayMasSalones;
            //Para cada docenteXClase
            for (Docentexclase docenteXClase : listaDocentexClase) {
                nHoras = docenteXClase.getNClsId().getNHoras().intValue();
                nSlnId = -1;
                nPrdId = -1;
                if( Math.random() < 0.5 ){
                    //Buscamos la clase en listaHorarioPadre1
                    horarioPadre = listaHorarioPadre1;
                    band2 = true;
                }else{
                    //Buscamos la clase en listaHorarioPadre2
                    horarioPadre = listaHorarioPadre2;
                    band2 = false;
                }
                //Por si se escoge al otro padre
                cont = 0;
                do{
                    //Obtiene el nSlnId y el nPrdId
                    if ( !buscarSalonYPeriodoEnHorario(docenteXClase.getNDcnClsId(),horarioPadre) ){
                        System.out.println("cruzarPadres:no encontró NDcnClsId = "+docenteXClase.getNDcnClsId());
                    }
                    //Buscamos la posición del periodo en la listaPeriodo
                    for (posPeriodo = 0; posPeriodo < listaPeriodo.size(); posPeriodo++) {
                        if( listaPeriodo.get(posPeriodo).getNPrdId() == nPrdId ){
                            break;
                        }              
                    }
                    asignoClase = false;
                    hayMasSalones = true;
                    //Se recorrerá la ClaseXSalon por si ya tiene asignado un docenteXClase
                    it = listaHMClaseXSalon.get(docenteXClase.getNDcnClsId()).entrySet().iterator();
                    do{
                        //Evaluamos si es un periodo válido a asignar en el horarioHijo
                        if( evaluarPeriodoYSalonPorAsignar( nHoras, docenteXClase.getNDcnClsId(),
                                nSlnId, posPeriodo, horarioHijo) ){
                            //Se le asigna un DocenteXClase a los periodos
                            for (j = 0; j < nHoras; j++) {
                                horarioHijo.get(nSlnId).put(listaPeriodo.get(posPeriodo+j).getNPrdId(), docenteXClase);
                            }
                            asignoClase = true;
                        }else{
                            if( it.hasNext() ){
                                e = (Map.Entry)it.next();
                                nSlnId = (Integer)e.getKey();
                                //System.out.println(e.getKey() + " " + e.getValue());
                            }else{
                                hayMasSalones = false;//No hay mas salones
                            }
                        }
                    }while( !asignoClase && hayMasSalones );
                    if( !asignoClase ){
                        cont++;
                        if( band2 ){
                            //Buscamos la clase en el otro padre: listaHorarioPadre1
                            horarioPadre = listaHorarioPadre2;
                        }else{
                            //Buscamos la clase en el otro padre: listaHorarioPadre2
                            horarioPadre = listaHorarioPadre1;
                        }
                    }
                }while( !asignoClase  && cont < 2 );
                if( !asignoClase )
                    System.out.println("ayudadita");
                //Si no ha asignado en un periodo y en un salón con los 2 padres
                if( cont == 2 ){
                    //Para cada salón factible
                    it = listaHMClaseXSalon.get(docenteXClase.getNDcnClsId()).entrySet().iterator();
                    while( it.hasNext() && !asignoClase ){
                        e = (Map.Entry)it.next();
                        nSlnId = (Integer)e.getKey();
                        for (posPeriodo = 0; posPeriodo < listaPeriodo.size(); posPeriodo++) {
                            if( evaluarPeriodoYSalonPorAsignar( nHoras, docenteXClase.getNDcnClsId(),
                                nSlnId, posPeriodo, horarioHijo) ){
                                    //&& evaluarDisponibilidadDocYAsg(nHoras,docenteXClase,posPeriodo) ){
                                //Se le asigna un DocenteXClase a los periodos
                                for (j = 0; j < nHoras; j++) {
                                    horarioHijo.get(nSlnId).put(listaPeriodo.get(posPeriodo+j).getNPrdId(), docenteXClase);
                                }
                                asignoClase = true;
                                break;
                            }
                        }
                    }
                    if( !asignoClase ){
                        System.out.println("No asignó: NDcnClsId="+docenteXClase.getNDcnClsId()+", "+
                                docenteXClase.getNClsId().getNAsgId().getVNombre());
                    }
                }
            }
            return horarioHijo;
        } catch (Exception ex) {
            Logger.getLogger(AGPrincipal.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }
    
    //Obtiene los códigos del salón y del periodo en el horario del padre para nDcnClsId
    private boolean buscarSalonYPeriodoEnHorario(int nDcnClsId, HashMap<Integer, HashMap<Integer, Docentexclase>> listaHorarioPadre){
        Docentexclase docenteXClase;            
        for (int i = 0; i < listaPeriodo.size(); i++) {               
            for (Salon salon : listaSalon) {
                docenteXClase = listaHorarioPadre.get(salon.getNSlnId()).get(listaPeriodo.get(i).getNPrdId());
                if( docenteXClase != null && 
                    docenteXClase.getNDcnClsId() == nDcnClsId ){
                    nSlnId = salon.getNSlnId();
                    nPrdId = listaPeriodo.get(i).getNPrdId();
                    nPosPrd = i;
                    return true;
                }
            }
        }
        return false;
    }
    
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Mutación">
    
    public HashMap<Integer, HashMap<Integer, Docentexclase>> mutacion(HashMap<Integer, HashMap<Integer, Docentexclase>> horarioHijo){        
        if( Math.random() < 0.5 ){
           horarioHijo =  N01(-1, horarioHijo);
        }else{
           horarioHijo =  N02(-1, horarioHijo);
        }
        return horarioHijo;
    }
    
    private HashMap<Integer, HashMap<Integer, Docentexclase>> LS01(HashMap<Integer, HashMap<Integer, Docentexclase>> horarioHijo){
        HashMap<Integer, HashMap<Integer, Docentexclase>> horarioHijoAux = inicializarHorario();
        int faHijoAux , faHijo = 0;
        Docentexclase docenteXClase;
        //Se realiza la copia del horarioHijo al horarioHijoAux
        for ( Periodo periodo : listaPeriodo ) {
            for (Salon salon : listaSalon ) {
                docenteXClase = horarioHijo.get(salon.getNSlnId()).get(periodo.getNPrdId());
                horarioHijoAux.get(salon.getNSlnId()).put(periodo.getNPrdId(), docenteXClase);                   
            }
        }
        
        faHijoAux =  evaluarFuncionAptitud(horarioHijoAux);
        
        for (int i = 0; i < listaDocentexClase.size(); i++) {
            docenteXClase = listaDocentexClase.get(i);
            //Aplicamos la estructura N01 al horarioHijo para todas las DcnCls
            N01(i,horarioHijo);
            faHijo = 99999999;            
            if( bandN01 ){
                faHijo = evaluarFuncionAptitud(horarioHijo);
            }
            //Si la Función de Aptitud después de aplicar la Estructura Vecinal
            //ha mejorado (disminuido) lo copiamos en faHijoAux
            if( faHijo < faHijoAux ){
                //Es mejor
                faHijoAux = faHijo;
                horarioHijoAux = inversaN01(docenteXClase.getNClsId().getNHoras().intValue(),
                                            nSlnIdAlt,altrPeriodo,i,true,horarioHijoAux);
            }else{
                if( bandN01 ){
                    //Si no ha mejorado, lo volvemos a su estado anterior
                    horarioHijo = inversaN01(docenteXClase.getNClsId().getNHoras().intValue(),
                                          nSlnIdAlt,altrPeriodo,i,false,horarioHijo);
                }
                //N01 no mejoró
                faHijo = 99999999;    
                N02(i,horarioHijo);
                if( bandN02 ){
                    faHijo = evaluarFuncionAptitud(horarioHijo);
                }
                if( faHijo < faHijoAux ){
                    //N02 mejoró
                    faHijoAux = faHijo;
                    horarioHijoAux = inversaN02(docenteXClase.getNClsId().getNHoras().intValue(),horarioHijoAux);
                }else{
                    if( bandN02 ){
                        //N02 no mejoró
                        horarioHijo = inversaN02(docenteXClase.getNClsId().getNHoras().intValue(),horarioHijo);
                    }
                }
            }
        }            
        return horarioHijoAux;
    }
    
    
    
    //N1: Selecciona un DocentexClase y lo cambia de salón y periodo
    //posDcnClsId: posición fijo de DcnCls que se hará el movimiento
    public HashMap<Integer, HashMap<Integer, Docentexclase>> N01 (int posDcnClsId, 
            HashMap<Integer, HashMap<Integer, Docentexclase>> horarioHijo){
        nSlnId = -1;
        nPosPrd = -1;
        nPrdId = -1;
        int altrDocentexClase;
        if( posDcnClsId == -1 )
            altrDocentexClase = (int)(Math.random()*(listaDocentexClase.size()-1));
        else
            altrDocentexClase = posDcnClsId;
        //System.out.println("N01");
        //Se selecciona un DocentexClase aleatoriamente
        int idDcnClsId = listaDocentexClase.get(altrDocentexClase).getNDcnClsId();
        int idDcnId = listaDocentexClase.get(altrDocentexClase).getNDcnId().getNDcnId();
        int nHoras = listaDocentexClase.get(altrDocentexClase).getNClsId().getNHoras().intValue();
        boolean asignado = false;
        int contador = 0;
        bandN01 = false;
        //System.out.println("1°"+listaDocentexClase.get(altrDocentexClase).getNClsId().getNAsgId().getVNombre());
        //Obtenemos la posiciòn de nSlnId y nPrdId, nPosPrd
        if( !buscarSalonYPeriodoEnHorario(idDcnClsId, horarioHijo) ){
            System.out.println("no encontró NDcnClsId = "+idDcnClsId);            
        }
        while( !asignado && contador < listaSalon.size()*listaPeriodo.size() ){
            contador++;
            altrSalon = (int)(Math.random()*(listaSalon.size()-1));
            altrPeriodo = (int)(Math.random()*(listaPeriodo.size()-1));
            //System.out.println("altrSalon="+altrSalon+",altrPeriodo"+altrPeriodo);
            nSlnIdAlt = listaSalon.get(altrSalon).getNSlnId();
            if( evaluarFuncionAptitudXEvento(nHoras, idDcnClsId, idDcnId, nSlnIdAlt, altrPeriodo, altrDocentexClase, horarioHijo) ){
                condensarParaEvento(nHoras,idDcnClsId,idDcnId,altrDocentexClase,horarioHijo);
                asignado = true; 
                bandN01 = true;
                for (int j = 0; j < nHoras; j++) {
                    //Asignamos el DocenteXClase al horario
                    horarioHijo.get(nSlnIdAlt).
                            put( listaPeriodo.get(altrPeriodo+j).getNPrdId(), 
                                listaDocentexClase.get(altrDocentexClase) );
                    //Eliminamos las clases anteriores
                    /*System.out.println("1!nSlnId="+nSlnId+",nPosPrd="+nPosPrd+",j="+j);
                    if( horarioHijo.get(nSlnId) == null || listaPeriodo.get(nPosPrd+j) == null ){
                        System.out.println("nSlnId="+nSlnId+",nPosPrd="+nPosPrd+",j="+j);
                    }*/
                    horarioHijo.get(nSlnId).
                        put(listaPeriodo.get(nPosPrd+j).getNPrdId(),null);
                }
            }
        }
       /* if( ! (contador < listaSalon.size()*listaPeriodo.size()) ){
            System.out.println("no se asignò:"+idDcnClsId+",asignado="+asignado);
        }*/
        return horarioHijo;
    }
    
    //
    private void condensarParaEvento(int nHoras, int idDcnClsId, int idDcnId, int altrDocentexClase, HashMap<Integer, HashMap<Integer, Docentexclase>> horario){
        if( listaPeriodo.get(altrPeriodo).getDtHora().getHours() == 8 ){
            //No hay más que condensar, es a las 8am
            return;
        }
        Docentexclase docentexclase = horario.get(listaSalon.get(nSlnIdAlt).getNSlnId()).
                                              get(listaPeriodo.get(altrPeriodo-1).getNPrdId());        
        if( listaPeriodo.get(altrPeriodo).getDtHora().getHours() == 9 &&
            docentexclase == null ){
            //Evaluamos si es periodo valido
            if( evaluarFuncionAptitudXEvento(nHoras, idDcnClsId, idDcnId, nSlnIdAlt, altrPeriodo-1, altrDocentexClase, horario) ){
                //Cambiamos los id de Salon y Periodo para N01
                altrPeriodo = altrPeriodo-1;
            }
        }else if( listaPeriodo.get(altrPeriodo).getDtHora().getHours() > 9 &&
            docentexclase == null ){
            Docentexclase docentexclase2 = horario.get(listaSalon.get(nSlnIdAlt).getNSlnId()).
                                              get(listaPeriodo.get(altrPeriodo-2).getNPrdId());
            //Evaluamos si es periodo valido
            if( docentexclase2 != null && 
                evaluarFuncionAptitudXEvento(nHoras, idDcnClsId, idDcnId, nSlnIdAlt, altrPeriodo-1, altrDocentexClase, horario) ){
                //Cambiamos los id de Salon y Periodo para N01
                altrPeriodo = altrPeriodo-1;
            }
        }
    }    
    
    //Evalua la Funciòn de Aptitud para un Evento, si no viola las restricciones duras
    private boolean evaluarFuncionAptitudXEvento(int nHoras, int idDcnClsId, int idDcnId, int nSlnIdAlt, int altrPeriodo, int altrDocentexClase, HashMap<Integer, HashMap<Integer, Docentexclase>> horario){
        if( evaluarPeriodoYSalonPorAsignar(nHoras,idDcnClsId,nSlnIdAlt,altrPeriodo,horario) && 
            evaluarUnicidadDocenteEnPeriodoXHoras(nHoras, idDcnId, altrPeriodo, horario) &&
            evaluarDisponibilidadDocYAsg(nHoras, listaDocentexClase.get(altrDocentexClase), altrPeriodo, -1)  &&
            evaluarConflictos(nHoras, listaDocentexClase.get(altrDocentexClase), altrPeriodo, horario)
                ){
            return true;
        }
        return false;
    }
    
    //Evalua la Funciòn de Aptitud para un Evento, si no viola las restricciones duras
    private boolean evaluarFuncionAptitudXEventoN02(int nHoras, int idDcnClsId, int idDcnId,int nSlnId, int altrPeriodo, int altrDocentexClase, HashMap<Integer, HashMap<Integer, Docentexclase>> horario){
        if( listaHMClaseXSalon.get(idDcnClsId).get(nSlnId) != null  && listaPeriodo.size() > (altrPeriodo+nHoras)/*&& 
            evaluarUnicidadDocenteEnPeriodoXHoras(nHoras, idDcnId, altrPeriodo, horario) &&
            evaluarDisponibilidadDocYAsg(nHoras, listaDocentexClase.get(altrDocentexClase), altrPeriodo, -1)*/
                ){
            return true;
        }
        return false;
    }
    
    //Realiza la operación que mejoro en el horarioHijo, sino mejoró lo invierte
    private HashMap<Integer, HashMap<Integer, Docentexclase>> inversaN01(int nHoras, int nSlnIdAlt, int altrPeriodo, int posDcnClsId,boolean band, HashMap<Integer, HashMap<Integer, Docentexclase>> horario){
        try{
        if ( band ){
            //Se hace el intercambio, mejoró
            for (int j = 0; j < nHoras; j++) {
                //Asignamos el DocenteXClase al horario
                horario.get(nSlnIdAlt).
                        put( listaPeriodo.get(altrPeriodo+j).getNPrdId(), 
                            horario.get(nSlnId).
                    get(listaPeriodo.get(nPosPrd+j).getNPrdId()) );
                //Eliminamos las clases anteriores
                horario.get(nSlnId).
                    put(listaPeriodo.get(nPosPrd+j).getNPrdId(),null);
            }            
        }else{
            //Se revierte el cambio
            for (int j = 0; j < nHoras; j++) {
                //Se vuelve a asignar el DocenteXClase al horario                
                horario.get(nSlnId).
                    put(listaPeriodo.get(nPosPrd+j).getNPrdId(),
                    listaDocentexClase.get(posDcnClsId));
                //Se elimina el anterior movimiento que no mejoró
                horario.get(nSlnIdAlt).
                        put( listaPeriodo.get(altrPeriodo+j).getNPrdId(), 
                             null);                
            }
        }
        }catch(Exception ex){ 
            System.out.println("ex="+ex.getMessage());
        }
        return horario;
    }
    
    //Realiza la operación que mejoro en el horarioHijo, sino mejoró lo invierte
    private HashMap<Integer, HashMap<Integer, Docentexclase>> inversaN02(int nHoras, HashMap<Integer, HashMap<Integer, Docentexclase>> horario){
        try{
        //Intercambiamos las clases        
            Docentexclase docentexclase = horario.get(nSlnId01).get(listaPeriodo.get(nPosPrdId01).getNPrdId());
            for(int y = 0; y < nHoras; y++){
                //Copiamos la clase que está en 02 a 01
                horario.get(nSlnId01).put(listaPeriodo.get(nPosPrdId01+y).getNPrdId(), 
                        horario.get(nSlnId02).get(listaPeriodo.get(nPosPrdId02+y).getNPrdId()));
                horario.get(nSlnId02).put(listaPeriodo.get(nPosPrdId02+y).getNPrdId(), docentexclase);
            } 
        }catch(Exception ex){
            System.out.println("ex="+ex.getMessage());
        }    
        return horario;
    }
    
    public HashMap<Integer, HashMap<Integer, Docentexclase>> N02 (int posDcnClsId, HashMap<Integer, HashMap<Integer, Docentexclase>> horarioHijo){
        int altrDcnXCls01, altrDcnXCls02, nDcnClsId01, nDcnClsId02, contador = 0;   
        Docentexclase docentexclase;
        boolean band01, band02;
        nPosPrdId01 = -1;
        nPosPrdId02 = -1;
        nSlnId01 = -1;
        nSlnId02 = -1;
        boolean flag01;
        boolean flag02;
        bandN02 = false;
        //System.out.println("N02");
        //Se obtiene el 1° DocentexClase
        if( posDcnClsId == -1 )
            altrDcnXCls01 = (int)(Math.random()*(listaDocentexClase.size()-1));
        else
            altrDcnXCls01 = posDcnClsId;
        //Código del 1° DocentexClase
        nDcnClsId01 = listaDocentexClase.get(altrDcnXCls01).getNDcnClsId();
        //Cantidad de horas del 1° DocentexClase
        int nHoras = listaDocentexClase.get(altrDcnXCls01).getNClsId().getNHoras().intValue();
        do{
            band01 = false;
            band02 = false;
            //Se obtiene el 2° DocentexClase, diferente al 1º 
            //y con la misma cantidad de horas de ditacto
            do{
                contador++;
                altrDcnXCls02 = (int)(Math.random()*(listaDocentexClase.size()-1));
                nDcnClsId02 = listaDocentexClase.get(altrDcnXCls02).getNDcnClsId();
            }while( altrDcnXCls01 == altrDcnXCls02 || 
                    listaDocentexClase.get(altrDcnXCls02).getNClsId().getNHoras().intValue() != 
                    listaDocentexClase.get(altrDcnXCls01).getNClsId().getNHoras().intValue() );
            //Buscamos el nSlnId y nPrdId para las 2 clases
            for (int i = 0; i < listaPeriodo.size() && (!band01 || !band02); i++) {
                for (int j = 0; j < listaSalon.size() && (!band01 || !band02); j++) {
                    docentexclase = horarioHijo.get(listaSalon.get(j).getNSlnId()).get(listaPeriodo.get(i).getNPrdId());
                    if( docentexclase != null && 
                        docentexclase.getNDcnClsId() == nDcnClsId01 && !band01 ){
                        nSlnId01 = listaSalon.get(j).getNSlnId();
                        nPosPrdId01 = i;
                        band01 = true;
                    }else if( docentexclase != null && 
                        docentexclase.getNDcnClsId() == nDcnClsId02 && !band02 ){
                        nSlnId02 = listaSalon.get(j).getNSlnId();
                        nPosPrdId02 = i;
                        band02 = true;
                    }
                }
            }
            flag01 = evaluarFuncionAptitudXEventoN02(nHoras, nDcnClsId01, listaDocentexClase.get(altrDcnXCls01).getNDcnId().getNDcnId() , 
                        nSlnId02, nPosPrdId02, altrDcnXCls01, horarioHijo);
            flag02 = evaluarFuncionAptitudXEventoN02(nHoras, nDcnClsId02, listaDocentexClase.get(altrDcnXCls02).getNDcnId().getNDcnId() , 
                        nSlnId01, nPosPrdId01, altrDcnXCls02, horarioHijo);
          //  aux++;
        }while( (!flag01 || !flag02) && contador < listaDocentexClase.size() );
        
        bandN02 = flag01 && flag02;
        if( bandN02 ){
            //Intercambiamos las clases        
            docentexclase = horarioHijo.get(nSlnId01).get(listaPeriodo.get(nPosPrdId01).getNPrdId());
            for(int y = 0; y < nHoras; y++){
                //Copiamos la clase que está en 02 a 01
                horarioHijo.get(nSlnId01).put(listaPeriodo.get(nPosPrdId01+y).getNPrdId(), 
                        horarioHijo.get(nSlnId02).get(listaPeriodo.get(nPosPrdId02+y).getNPrdId()));
                horarioHijo.get(nSlnId02).put(listaPeriodo.get(nPosPrdId02+y).getNPrdId(), docentexclase);
            }
        }
        return horarioHijo;
    }
    
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Reemplazar">
    
    public void reemplazar(HashMap<Integer, HashMap<Integer, Docentexclase>> hijo){
        int indice = obtenerPosPeorSolucion();
        int fa = evaluarFuncionAptitud(hijo);
        System.out.println("Indice peor solucion:"+indice +" FA:"+listaHorariosFA.get(indice));
        System.out.println("FA del hijo:"+fa);
        listaHorarios.set(indice, hijo);
        listaHorariosFA.set(indice, fa);        
    }
    
    public int obtenerPosPeorSolucion(){
        int peorsolucion = 0;
        int indice = -1;         
        for(int i=0; i<listaHorariosFA.size(); i++){
            //System.out.println("Horario : "+i +"Valor de Funcion de Adaptacion :"+auxpeorsolucion);
            //System.out.println("Horario : "+i +"Valor de Funcion de Adaptacion PS :"+listaHorariosFA.get(i)+" "+"FA="+evaluarFuncionAptitud(listaHorarios.get(i)));
            if( listaHorariosFA.get(i) > peorsolucion ){
                peorsolucion = listaHorariosFA.get(i);
                indice = i;
            }
        }
        vFuncionAptitud = listaHorariosFA.get(indice);
        return indice;        
    }
    
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Mejor Solución">        
    
    public int  obtenerMejorSolucion(){ 
        int mejorsolucion=999999999;
        int indice = 0;       
        for(int i=0; i<listaHorariosFA.size(); i++){
            System.out.println("Horario : "+i +"Valor de Funcion de Adaptacion MS :"+listaHorariosFA.get(i)+" "+"FA="+evaluarFuncionAptitud(listaHorarios.get(i)));
            if( listaHorariosFA.get(i) < mejorsolucion ){
                //System.out.println("Individuo i"+i+" FA:"+listaHorariosFA.get(i));
                mejorsolucion = listaHorariosFA.get(i);
                indice = i;
            }
        }
        evaluarFuncionAptitud(listaHorarios.get(indice));
        //vFuncionAptitud = mejorsolucion;
        System.out.println("La mejor solucion:"+vFuncionAptitud +",i="+indice);
        int contfilas;
        int contcolumnas = 1;
        //Se guardará el horario con mejor FA
        for ( Periodo periodo : listaPeriodo ) {
            contfilas = 1;
            //contcolumnas = 1;
            for (Salon salon : listaSalon ) {
                //Docentexclase docenteXClase = listaHorarioSalon.get(salon.getNSlnId()).get(periodo.getNPrdId());
                Docentexclase docenteXClase = listaHorarios.get(indice).get(salon.getNSlnId()).get(periodo.getNPrdId());
                if( docenteXClase == null ){
                    //System.out.println("null"+",("+contfilas+","+contcolumnas+")");
                    matrizHorario[contfilas-1][contcolumnas-1]= "";
                }else{ 
                    //System.out.println(docenteXClase.getNClsId().getNAsgId().getVNombre()+",("+contfilas+","+contcolumnas+")");
                    matrizHorario[contfilas-1][contcolumnas-1]= docenteXClase.getNClsId().getNAsgId().getVNombre() +","+docenteXClase.getNClsId().getNMdlDctId().getVNombre();
                }
                contfilas++;
            }
            contcolumnas++;
        } 
        
        System.out.println("FA="+evaluarFuncionAptitud(listaHorarios.get(indice))+",indice="+indice);
        System.out.println("cntRD02="+cntRD02+"\ncntRD05="+cntRD05+"\ncntRD07="+
                cntRD07+"\ncntRD09="+cntRD09+"\ncntRD10="+cntRD10+"\ncntRD11="+cntRD11);
        System.out.println("Total="+(cntRD02+cntRD05+cntRD07+cntRD09+cntRD10+cntRD11));
        return indice;
    }

    //</editor-fold>
            
    //<editor-fold defaultstate="collapsed" desc="Algoritmo Genético">
    
    public void algoritmoGenetico(){
        int posPadre1;
        indicemejorsolucion = 0;
        HashMap<Integer, HashMap<Integer, Docentexclase>> listaHorarioPadre1, listaHorarioPadre2;
        HashMap<Integer, HashMap<Integer, Docentexclase>> horarioHijo;
        obtenerDataParaAG();
        System.out.println("data inicial obtenida");
        inicializarPoblacion();
        System.out.println("Población inicializada");
        while( parada > 0){
            //seleccionamos 2 padres por torneo de tamaño 2      
            posPadre1 = seleccionarPosicionPadre(-1);
            listaHorarioPadre1 = listaHorarios.get(posPadre1);
            listaHorarioPadre2 = listaHorarios.get(seleccionarPosicionPadre(posPadre1));  
            //Cruzamiento
            if( Math.random() < Pc ){
                horarioHijo = cruzarPadres(listaHorarioPadre1, listaHorarioPadre2);
            }else{
                if( Math.random() < 0.5 ){
                    horarioHijo = listaHorarioPadre1;
                }else{
                    horarioHijo = listaHorarioPadre2;
                }                
            }
            //Mutación
            if( Math.random() < Pm ){
              horarioHijo = mutacion(horarioHijo);   
            }
            //Bùsqueda local
            horarioHijo = LS01(horarioHijo);
            //Reemplazar
            reemplazar(horarioHijo); 
            
            
            System.out.println("Por la iteración ..................."+parada);

            parada--;
            /*if(parada%130 == 0){
                Runtime garbage = Runtime.getRuntime();
                garbage.gc();
            }*/
        }
        indicemejorsolucion = obtenerMejorSolucion();
        
        descargarhorarioconsola();
        descargarhorarioxsalonconsola(indicemejorsolucion);       
        //verlistapdfconsola(indicemejorsolucion);
        //ReporteHorario reporteHorario = new ReporteHorario();
        //reporteHorario.generaPDF(listaHorarios, listaDocentexClase, listaSalon, listaPeriodo, indicemejorsolucion);
        //HorarioHijo = N01(HorarioHijo);
        System.out.println("Obtenemos la mejor solucion:");
        //obtenerMejorSolucion();
        //Realizamos la selección        
    }
    
    /*private HashMap<Integer, HashMap<Integer, Docentexclase>> condensarHorario(HashMap<Integer, HashMap<Integer, Docentexclase>> horario){
        Docentexclase docenteXClase;
        for(Salon salon : listaSalon){
            for
            docenteXClase = horario.get(salon.getNSlnId()).get(periodo.getNPrdId());
            
        }       
        return null;
    }*/
    
    public StreamedContent descargarpdf(HashMap<Integer, HashMap<Integer, Docentexclase>> individuovista, List<Salon> listaSalonvista, List<Periodo> listaPeriodovista, List<Docentexclase> listaDocentexClasevista ){
                ReporteHorariovista reporteHorariovista = new ReporteHorariovista();
                 reporteHorariovista.generaPDF(individuovista, listaDocentexClasevista, listaSalonvista, listaPeriodovista);
                StreamedContent file;
                InputStream stream;
                try {
                    //SimpleDateFormat fec = new SimpleDateFormat("yyyy-MM-dd");
                   // String fecha = fec.format(trabajo.getfInicioMigracion());
                    String archivomop ="Reportehorario.pdf";
                    //String nombreArchivo="/opt/migraciones/"+usuarioSesion.getUsuario()+"MOP_"+archivomop;   //nombre en donde va a buscar
                    String nombreArchivo="c:/horarios/"+archivomop;
                    //String nombreArchivo="/opt/horarios/"+archivomop;
                    
                    
                    //String nombreArchivo="D:/mop.docx";
                    String destino=archivomop;

  //                  System.out.println("Nombre Archivo"+nombreArchivo);
                    stream = new FileInputStream(nombreArchivo);
                    file = new DefaultStreamedContent(stream, "image/jpg", destino); 
                    return file;
                } catch (FileNotFoundException ex) {
                    //Logger.getLogger(newlistaproyectotrabajos.class.getName()).log(Level.SEVERE, null, ex);
                    return null;
                }
    }
    
    
    /*public void verlistapdf(int indice){
        System.out.println("Horario Fisi:");
        int idDcnCls = 0;
        int nHoras = 0;
        String asignatura = "";
        String modalidad = "";
        String dia = "";
        String aula = "";
        String horario = "";
        
        for(int m=0; m<listaDocentexClase.size(); m++){
            listaDocentexClase.get(m).getNCicId();
            idDcnCls = listaDocentexClase.get(m).getNDcnClsId();
            nHoras = listaDocentexClase.get(m).getNClsId().getNHoras().intValue();
            
            for (int i=0; i<listaSalon.size(); i++ ) {
                //System.out.println(""+salon.getNSlnId()+listaHorarioSalon.get(salon.getNSlnId())+" = ");
                //contcolumnas = 1;
               
                for (int j=0; j<listaPeriodo.size(); j++) {
                    
                    if(listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).get(listaPeriodo.get(j).getNPrdId())!=null){
                      Docentexclase docenteXClase = listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).get(listaPeriodo.get(j).getNPrdId());
                      //System.out.println("Indice:"+listaHorarioSalon.get(salon.getNSlnId()).get(periodo.getNPrdId()).getNDcnClsId());
                      if(idDcnCls == (int)listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).get(listaPeriodo.get(j).getNPrdId()).getNDcnClsId()){
                             asignatura = ""+listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).get(listaPeriodo.get(j).getNPrdId()).getNClsId().getNAsgId().getVNombre();
                             modalidad = ""+listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).get(listaPeriodo.get(j).getNPrdId()).getNClsId().getNMdlDctId().getVNombre();
                             horario = ""+listaPeriodo.get(j).getDtHora().getHours();
                             dia = ""+listaPeriodo.get(j).getNDia();
                             //aula = ""+listaPeriodo.get(j).get;
                             
                             System.out.println(""+asignatura+","+modalidad+", Dia:"+dia+",Horario:"+horario);
                             for (int k = 0; k < nHoras; k++) {
                                
                                listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).
                                        put( listaPeriodo.get(j+k).getNPrdId(), 
                                            null);                
                            }
                      }
             
                      
                    }
                }
            }
        }
    }*/
    
    public StreamedContent descargarhorarioxsalon(HashMap<Integer, HashMap<Integer, Docentexclase>> individuovista, List<Salon> listaSalonvista, List<Periodo> listaPeriodovista ){
                verlistahorarioxsalon(individuovista, listaSalonvista, listaPeriodovista);
                StreamedContent file;
                InputStream stream;
                try {
                    //SimpleDateFormat fec = new SimpleDateFormat("yyyy-MM-dd");
                   // String fecha = fec.format(trabajo.getfInicioMigracion());
                    String archivomop ="HorariosxSalon.xls";
                    //String nombreArchivo="/opt/migraciones/"+usuarioSesion.getUsuario()+"MOP_"+archivomop;   //nombre en donde va a buscar
                    
                    String nombreArchivo="c:/horarios/"+archivomop;
                    //String nombreArchivo="/opt/horarios/"+archivomop;
        
                    
                    //String nombreArchivo="D:/mop.docx";
                    String destino=archivomop;

  //                  System.out.println("Nombre Archivo"+nombreArchivo);
                    stream = new FileInputStream(nombreArchivo);
                    file = new DefaultStreamedContent(stream, "image/jpg", destino); 
                    return file;
                } catch (FileNotFoundException ex) {
                    //Logger.getLogger(newlistaproyectotrabajos.class.getName()).log(Level.SEVERE, null, ex);
                    return null;
                }
    }
    
    public void verlistahorarioxsalon(HashMap<Integer, HashMap<Integer, Docentexclase>> individuovista, List<Salon> listaSalonvista, List<Periodo> listaPeriodovista){
        try {
            FileOutputStream archivo = null;
                int nfilas=0;
                HSSFSheet sheet;
                HSSFRow row1;
                HSSFCell a1;
                OutputStream output = null;
                HSSFWorkbook libro = new HSSFWorkbook();
                
                HSSFCellStyle cellStyle = libro.createCellStyle();    
                cellStyle.setFillForegroundColor(HSSFColor.GREEN.index);  
                cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
                int fila = 0; 
                int columna = 0;
                //"c:\\"+nomArch+".xls"
                //archivo = new FileOutputStream("/opt/migraciones/"+usuarioSesion.getUsuario()+"MOP_Migraciones.xls");
                archivo = new FileOutputStream("c:/horarios/HorariosxSalon.xls");              
                //archivo = new FileOutputStream("/opt/horarios/HorariosxSalon.xls");
                for (int i=0; i<listaSalonvista.size(); i++ ) {
                    sheet = libro.createSheet(""+listaSalonvista.get(i).getVNombre());
                    nfilas=0;
                //System.out.println(""+salon.getNSlnId()+listaHorarioSalon.get(salon.getNSlnId())+" = ");
                //contcolumnas = 1;
                    if(nfilas==0){
                            row1  = sheet.createRow((short) nfilas);
                            a1   = row1.createCell((short) 0);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Hora");
                            
                            a1   = row1.createCell((short) 1);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Lunes");
                            
                            a1   = row1.createCell((short) 2);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Martes");
                            
                            a1   = row1.createCell((short) 3);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Miercoles");
                            
                            a1   = row1.createCell((short) 4);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Jueves");
                            
                            a1   = row1.createCell((short) 5);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Viernes");
                            
                            a1   = row1.createCell((short) 6);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Sabado");
                            nfilas++;
                 }    

                            for(int m=0; m<14; m++){
                                row1  = sheet.createRow((short) nfilas);
                                a1   = row1.createCell((short) 0);
                                //a1.setCellStyle(cellStyle);
                                a1.setCellValue(listahoras.get(m));
                                
                                for(int k=0; k<6; k++){
                                    columna = k*14+(1+m);
                                    //System.out.println("Columna:"+columna);
                                    Docentexclase docenteXClase = individuovista.get(listaSalonvista.get(i).getNSlnId()).get(listaPeriodovista.get(columna-1).getNPrdId());
                                    a1   = row1.createCell((short) (k+1));
                                    //a1.setCellStyle(cellStyle);
                                    if(docenteXClase != null){
                                        a1.setCellValue(docenteXClase.getNClsId().getNAsgId().getVNombre() +","+docenteXClase.getNClsId().getNMdlDctId().getVNombre());
                                    }else{
                                        a1.setCellValue("");
                                    }
                                    
                                
                                }
                                nfilas++;
                                
                            }

                            //nfilas++;
                }  
            libro.write(archivo);
            archivo.close();
            /*FacesMessage msg = new FacesMessage("Se cargo exitosamente, Espere un momento.");  
            FacesContext.getCurrentInstance().addMessage(null, msg);*/
        } catch (IOException ex) {
            Logger.getLogger(AGPrincipal.class.getName()).log(Level.SEVERE, null, ex);
        }
        

            
            
      
        
    }
            
    public StreamedContent descargarhorario(String matrizHorariovista[][], List<Salon> listaSalonvista, List<Periodo> listaPeriodovista){
                verlista(matrizHorariovista, listaSalonvista, listaPeriodovista);
                StreamedContent file;
                InputStream stream = null;
                try {
                    //SimpleDateFormat fec = new SimpleDateFormat("yyyy-MM-dd");
                   // String fecha = fec.format(trabajo.getfInicioMigracion());
                    
                    
                    String archivomop ="Horarios.xls";
                    //String nombreArchivo="/opt/migraciones/"+usuarioSesion.getUsuario()+"MOP_"+archivomop;   //nombre en donde va a buscar
                    String nombreArchivo="c:/horarios/"+archivomop;
                    //String nombreArchivo="/opt/horarios/"+archivomop;
                    
                    //String nombreArchivo="D:/mop.docx";
                    String destino=archivomop;

  //                  System.out.println("Nombre Archivo"+nombreArchivo);
                    stream = new FileInputStream(nombreArchivo);
                    file = new DefaultStreamedContent(stream, "image/jpg", destino); 
                    return file;
                } catch (FileNotFoundException ex) {
                    //Logger.getLogger(newlistaproyectotrabajos.class.getName()).log(Level.SEVERE, null, ex);
                    return null;
                }
    }
    
    public void verlista(String matrizHorariovista[][], List<Salon> listaSalonvista, List<Periodo> listaPeriodovista){
        try {
            FileOutputStream archivo = null;
            int nfilas=0;
            
                HSSFRow row1;
                HSSFCell a1;
                OutputStream output = null;
                HSSFWorkbook libro = new HSSFWorkbook();
                
                HSSFCellStyle cellStyle = libro.createCellStyle();    
                cellStyle.setFillForegroundColor(HSSFColor.GREEN.index);  
                cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); 
                //"c:\\"+nomArch+".xls"
                //archivo = new FileOutputStream("/opt/migraciones/"+usuarioSesion.getUsuario()+"MOP_Migraciones.xls");
                archivo = new FileOutputStream("c:/horarios/Horarios.xls");
                //archivo = new FileOutputStream("/opt/horarios/Horarios.xls");
                
                HSSFSheet sheet = libro.createSheet("Exportar Horario");           
                for(int i=0; i<listaSalonvista.size(); i++){
                       if(i==0){
                            row1  = sheet.createRow((short) nfilas);
                            a1   = row1.createCell((short) 0);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Salon");
                            for(int k=1; k<=listaPeriodovista.size(); k++){
                                a1   = row1.createCell((short) k);
                                a1.setCellStyle(cellStyle);
                                a1.setCellValue("P"+k);  
                            }
                           
                            nfilas++;
  
                       }
                       
                            row1  = sheet.createRow((short) nfilas);
                            a1   = row1.createCell((short) 0);	
                            a1.setCellValue(listaSalonvista.get(i).getVNombre()); 
                            for(int j=1; j<=listaPeriodovista.size(); j++){
                                a1   = row1.createCell((short) j);
                                System.out.println("Valor:"+matrizHorariovista[i][j-1]);
                                a1.setCellValue(matrizHorariovista[i][j-1]);  
                            }
                                                       
                            nfilas++;
                       }   
            libro.write(archivo);
            archivo.close();
            /*FacesMessage msg = new FacesMessage("Se cargo exitosamente, Espere un momento.");  
            FacesContext.getCurrentInstance().addMessage(null, msg);*/
        } catch (IOException ex) {
            Logger.getLogger(AGPrincipal.class.getName()).log(Level.SEVERE, null, ex);
        }
           
    }
    
    
    public StreamedContent descargarhorarioxsalonconsola(int indice){
                verlistahorarioxsalonconsola(indice);
                StreamedContent file;
                InputStream stream;
                try {
                    //SimpleDateFormat fec = new SimpleDateFormat("yyyy-MM-dd");
                   // String fecha = fec.format(trabajo.getfInicioMigracion());
                    String archivomop ="HorariosxSalon.xls";
                    //String nombreArchivo="/opt/migraciones/"+usuarioSesion.getUsuario()+"MOP_"+archivomop;   //nombre en donde va a buscar
                    String nombreArchivo="d:\\"+archivomop;
                    
                    //String nombreArchivo="D:/mop.docx";
                    String destino=archivomop;

  //                  System.out.println("Nombre Archivo"+nombreArchivo);
                    stream = new FileInputStream(nombreArchivo);
                    file = new DefaultStreamedContent(stream, "image/jpg", destino); 
                    return file;
                } catch (FileNotFoundException ex) {
                    //Logger.getLogger(newlistaproyectotrabajos.class.getName()).log(Level.SEVERE, null, ex);
                    return null;
                }
    }
    
    public void verlistahorarioxsalonconsola(int indice){
        try {
            FileOutputStream archivo = null;
                int nfilas=0;
                HSSFSheet sheet;
                HSSFRow row1;
                HSSFCell a1;
                OutputStream output = null;
                HSSFWorkbook libro = new HSSFWorkbook();
                
                HSSFCellStyle cellStyle = libro.createCellStyle();    
                cellStyle.setFillForegroundColor(HSSFColor.GREEN.index);  
                cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
                int fila = 0; 
                int columna = 0;
                //"c:\\"+nomArch+".xls"
                //archivo = new FileOutputStream("/opt/migraciones/"+usuarioSesion.getUsuario()+"MOP_Migraciones.xls");
                archivo = new FileOutputStream("d:\\HorariosxSalon.xls");
                
                for (int i=0; i<listaSalon.size(); i++ ) {
                    sheet = libro.createSheet(""+listaSalon.get(i).getVNombre());
                    nfilas=0;
                //System.out.println(""+salon.getNSlnId()+listaHorarioSalon.get(salon.getNSlnId())+" = ");
                //contcolumnas = 1;
                    if(nfilas==0){
                            row1  = sheet.createRow((short) nfilas);
                            a1   = row1.createCell((short) 0);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Hora");
                            
                            a1   = row1.createCell((short) 1);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Lunes");
                            
                            a1   = row1.createCell((short) 2);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Martes");
                            
                            a1   = row1.createCell((short) 3);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Miercoles");
                            
                            a1   = row1.createCell((short) 4);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Jueves");
                            
                            a1   = row1.createCell((short) 5);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Viernes");
                            
                            a1   = row1.createCell((short) 6);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Sabado");
                            nfilas++;
                 }    

                            for(int m=0; m<14; m++){
                                row1  = sheet.createRow((short) nfilas);
                                a1   = row1.createCell((short) 0);
                                //a1.setCellStyle(cellStyle);
                                a1.setCellValue(listahoras.get(m));
                                
                                for(int k=0; k<6; k++){
                                    columna = k*14+(1+m);
                                    //System.out.println("Columna:"+columna);
                                    Docentexclase docenteXClase = listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).get(listaPeriodo.get(columna-1).getNPrdId());
                                    a1   = row1.createCell((short) (k+1));
                                    //a1.setCellStyle(cellStyle);
                                    if(docenteXClase != null){
                                        a1.setCellValue(docenteXClase.getNClsId().getNAsgId().getVNombre() +","+docenteXClase.getNClsId().getNMdlDctId().getVNombre());
                                    }else{
                                        a1.setCellValue("");
                                    }
                                    
                                
                                }
                                nfilas++;
                                
                            }

                            //nfilas++;
                }  
            libro.write(archivo);
            archivo.close();
            /*FacesMessage msg = new FacesMessage("Se cargo exitosamente, Espere un momento.");  
            FacesContext.getCurrentInstance().addMessage(null, msg);*/
        } catch (IOException ex) {
            Logger.getLogger(AGPrincipal.class.getName()).log(Level.SEVERE, null, ex);
        }
        

            
            
      
        
    }
    
    
    public StreamedContent descargarhorarioconsola(){
                verlistaconsola();
                StreamedContent file;
                InputStream stream = null;
                try {
                    //SimpleDateFormat fec = new SimpleDateFormat("yyyy-MM-dd");
                   // String fecha = fec.format(trabajo.getfInicioMigracion());
                    String archivomop ="Horarios.xls";
                    //String nombreArchivo="/opt/migraciones/"+usuarioSesion.getUsuario()+"MOP_"+archivomop;   //nombre en donde va a buscar
                    String nombreArchivo="d:\\"+archivomop;
                    
                    //String nombreArchivo="D:/mop.docx";
                    String destino=archivomop;

  //                  System.out.println("Nombre Archivo"+nombreArchivo);
                    stream = new FileInputStream(nombreArchivo);
                    file = new DefaultStreamedContent(stream, "image/jpg", destino); 
                    return file;
                } catch (FileNotFoundException ex) {
                    //Logger.getLogger(newlistaproyectotrabajos.class.getName()).log(Level.SEVERE, null, ex);
                    return null;
                }
    }
    
    public void verlistaconsola(){
        try {
            FileOutputStream archivo = null;
            int nfilas=0;
            
                HSSFRow row1;
                HSSFCell a1;
                OutputStream output = null;
                HSSFWorkbook libro = new HSSFWorkbook();
                
                HSSFCellStyle cellStyle = libro.createCellStyle();    
                cellStyle.setFillForegroundColor(HSSFColor.GREEN.index);  
                cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); 
                //"c:\\"+nomArch+".xls"
                //archivo = new FileOutputStream("/opt/migraciones/"+usuarioSesion.getUsuario()+"MOP_Migraciones.xls");
                archivo = new FileOutputStream("d:\\Horarios.xls");
                HSSFSheet sheet = libro.createSheet("Exportar Horario");           
                for(int i=0; i<listaSalon.size(); i++){
                       if(i==0){
                            row1  = sheet.createRow((short) nfilas);
                            a1   = row1.createCell((short) 0);
                            a1.setCellStyle(cellStyle);
                            a1.setCellValue("Salon");
                            for(int k=1; k<=listaPeriodo.size(); k++){
                                a1   = row1.createCell((short) k);
                                a1.setCellStyle(cellStyle);
                                a1.setCellValue("P"+k);  
                            }
                           
                            nfilas++;
  
                       }
                       
                            row1  = sheet.createRow((short) nfilas);
                            a1   = row1.createCell((short) 0);	
                            a1.setCellValue(listaSalon.get(i).getVNombre()); 
                            for(int j=1; j<=listaPeriodo.size(); j++){
                                a1   = row1.createCell((short) j);	
                                a1.setCellValue(matrizHorario[i][j-1]);  
                            }
                                                       
                            nfilas++;
                       }
     //                  System.out.println("Codigo de trabajo"+trabajosfiltrados.get(i).getCodigo());
                       
                   
                
            libro.write(archivo);
            archivo.close();
            /*FacesMessage msg = new FacesMessage("Se cargo exitosamente, Espere un momento.");  
            FacesContext.getCurrentInstance().addMessage(null, msg);*/
        } catch (IOException ex) {
            Logger.getLogger(AGPrincipal.class.getName()).log(Level.SEVERE, null, ex);
        }
           
    }
    
        public void verlistapdfconsola(int indice){
        System.out.println("Horario Fisi:");
        int idDcnCls = 0;
        int nHoras = 0;
        String asignatura = "";
        String modalidad = "";
        String dia = "";
        String aula = "";
        String horario = "";
        
        for(int m=0; m<listaDocentexClase.size(); m++){
            listaDocentexClase.get(m).getNCicId();
            idDcnCls = listaDocentexClase.get(m).getNDcnClsId();
            nHoras = listaDocentexClase.get(m).getNClsId().getNHoras().intValue();
            
            for (int i=0; i<listaSalon.size(); i++ ) {
                //System.out.println(""+salon.getNSlnId()+listaHorarioSalon.get(salon.getNSlnId())+" = ");
                //contcolumnas = 1;
               
                for (int j=0; j<listaPeriodo.size(); j++) {
                    
                    if(listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).get(listaPeriodo.get(j).getNPrdId())!=null){
                      Docentexclase docenteXClase = listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).get(listaPeriodo.get(j).getNPrdId());
                      //System.out.println("Indice:"+listaHorarioSalon.get(salon.getNSlnId()).get(periodo.getNPrdId()).getNDcnClsId());
                      if(idDcnCls == (int)listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).get(listaPeriodo.get(j).getNPrdId()).getNDcnClsId()){
                             asignatura = ""+listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).get(listaPeriodo.get(j).getNPrdId()).getNClsId().getNAsgId().getVNombre();
                             modalidad = ""+listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).get(listaPeriodo.get(j).getNPrdId()).getNClsId().getNMdlDctId().getVNombre();
                             horario = ""+listaPeriodo.get(j).getDtHora().getHours();
                             dia = ""+listaPeriodo.get(j).getNDia();
                             //aula = ""+listaPeriodo.get(j).get;
                             
                             System.out.println(""+asignatura+","+modalidad+", Dia:"+dia+",Horario:"+horario);
                             for (int k = 0; k < nHoras; k++) {
                                
                                listaHorarios.get(indice).get(listaSalon.get(i).getNSlnId()).
                                        put( listaPeriodo.get(j+k).getNPrdId(), 
                                            null);                
                            }
                      }
             
                      
                    }
                }
            }
        }
    }


    public static void main(String[] args){
        AGPrincipal agPrincipal = new AGPrincipal();
        //agPrincipal.validarHorario();
        agPrincipal.algoritmoGenetico();                
    }
    
    public void validarHorario(){
        obtenerDataParaAG();
        HashMap<Integer, HashMap<Integer, Docentexclase>> horario = inicializarHorario();
        for (int i = 0; i < listaPeriodoXSalon.size(); i++) {
            nSlnId = listaPeriodoXSalon.get(i).getSlnId().getNSlnId();
            nPrdId = listaPeriodoXSalon.get(i).getNPrdId().getNPrdId();
            horario.get(nSlnId).put(nPrdId, listaPeriodoXSalon.get(i).getNDcnClsId());
        }
        int fa = evaluarFuncionAptitud(horario);
        System.out.println("fa="+fa);
        System.out.println("cntRD02="+cntRD02+"\ncntRD05="+cntRD05+"\ncntRD07="+
                cntRD07+"\ncntRD09="+cntRD09+"\ncntRD10="+cntRD10+"\ncntRD11="+cntRD11);
    }

    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="GETTER and SETTER">
    
    public String[][] getMatrizHorario() {
        return matrizHorario;
    }

    public void setMatrizHorario(String[][] matrizHorario) {
        this.matrizHorario = matrizHorario;
    }

    public int getvFuncionAptitud() {
        return vFuncionAptitud;
    }

    public void setvFuncionAptitud(int vFuncionAptitud) {
        this.vFuncionAptitud = vFuncionAptitud;
    }
    
    public int getVfunciondeadaptacion() {
        return vfunciondeadaptacion;
    }

    public void setVfunciondeadaptacion(int vfunciondeadaptacion) {
        this.vfunciondeadaptacion = vfunciondeadaptacion;
    }
    
    public int getIndicemejorsolucion() {
        return indicemejorsolucion;
    }

    public void setIndicemejorsolucion(int indicemejorsolucion) {
        this.indicemejorsolucion = indicemejorsolucion;
    }

    public int getIndicepeorsolucion() {
        return indicepeorsolucion;
    }

    public void setIndicepeorsolucion(int indicepeorsolucion) {
        this.indicepeorsolucion = indicepeorsolucion;
    }

    public List<Periodo> getListaPeriodo() {
        return listaPeriodo;
    }

    public void setListaPeriodo(List<Periodo> listaPeriodo) {
        this.listaPeriodo = listaPeriodo;
    }

    public List<HashMap<Integer, HashMap<Integer, Docentexclase>>> getListaHorarios() {
        return listaHorarios;
    }

    public void setListaHorarios(List<HashMap<Integer, HashMap<Integer, Docentexclase>>> listaHorarios) {
        this.listaHorarios = listaHorarios;
    }
    
    //</editor-fold>
    
}
